1
|
|
|
var eventQueue = []; |
2
|
|
|
var svg; |
3
|
|
|
var element; |
4
|
|
|
var drawingArea; |
5
|
|
|
var width; |
6
|
|
|
var height; |
7
|
|
|
var volume = 0.6; |
8
|
|
|
var orgRepoFilterNames = []; |
9
|
|
|
|
10
|
|
|
var scale_factor = 6, |
11
|
|
|
note_overlap = 2, |
12
|
|
|
note_timeout = 300, |
13
|
|
|
current_notes = 0, |
14
|
|
|
max_life = 20000; |
15
|
|
|
|
16
|
|
|
var svg_background_color_online = '#232323', |
17
|
|
|
svg_background_color_offline = '#232323', |
18
|
|
|
svg_text_color = '#FFFFFF', |
19
|
|
|
edit_color = '#FFFFFF', |
20
|
|
|
total_sounds = 51; |
21
|
|
|
|
22
|
|
|
var celesta = [], |
23
|
|
|
clav = [], |
24
|
|
|
swells = [], |
25
|
|
|
all_loaded = false; |
26
|
|
|
|
27
|
|
|
var protocol = 'ws://'; |
28
|
|
|
|
29
|
|
|
if (window.location.protocol === "https:") { |
30
|
|
|
protocol = 'wss://'; |
31
|
|
|
} |
32
|
|
|
|
33
|
|
|
var socket = new WebSocket(protocol + window.location.host + '/ws'); |
34
|
|
|
|
35
|
|
|
socket.addEventListener("message", function (data) { |
36
|
|
|
var json = JSON.parse(data.data); |
37
|
|
|
|
38
|
|
|
if (json.hasOwnProperty('connectedUsers')) { |
39
|
|
|
$('.online-users-count').html(json.connectedUsers); |
40
|
|
|
|
41
|
|
|
return; |
42
|
|
|
} |
43
|
|
|
|
44
|
|
|
json.forEach(function (event) { |
45
|
|
|
if (!isEventInQueue(event)) { |
46
|
|
|
// Filter out events only specified by the user |
47
|
|
|
if (orgRepoFilterNames != []) { |
48
|
|
|
// Don't consider pushes to github.io repos when org filter is on |
49
|
|
|
if (new RegExp(orgRepoFilterNames.join("|")).test(event.repoName) && event.repoName.indexOf('github.io') == -1) { |
50
|
|
|
eventQueue.push(event); |
51
|
|
|
} |
52
|
|
|
} else { |
53
|
|
|
eventQueue.push(event); |
54
|
|
|
} |
55
|
|
|
} |
56
|
|
|
}); |
57
|
|
|
|
58
|
|
|
// Don't let the eventQueue grow more than 1000 |
59
|
|
|
if (eventQueue.length > 1000) eventQueue = eventQueue.slice(0, 1000); |
|
|
|
|
60
|
|
|
}); |
61
|
|
|
|
62
|
|
|
socket.onopen = function(e){ |
|
|
|
|
63
|
|
|
$('svg').css('background-color', svg_background_color_online); |
64
|
|
|
$('header').css('background-color', svg_background_color_online); |
65
|
|
|
$('.offline-text').css('visibility', 'hidden'); |
66
|
|
|
$('.events-remaining-text').css('visibility', 'visible'); |
67
|
|
|
$('.events-remaining-value').css('visibility', 'visible'); |
68
|
|
|
$('.online-users-div').css('visibility', 'visible'); |
69
|
|
|
}; |
70
|
|
|
|
71
|
|
|
socket.onclose = function(e){ |
|
|
|
|
72
|
|
|
$('svg').css('background-color', svg_background_color_offline); |
73
|
|
|
$('header').css('background-color', svg_background_color_offline); |
74
|
|
|
$('.offline-text').css('visibility', 'visible'); |
75
|
|
|
$('.events-remaining-text').css('visibility', 'visible'); |
76
|
|
|
$('.events-remaining-value').css('visibility', 'visible'); |
77
|
|
|
}; |
78
|
|
|
|
79
|
|
|
socket.onerror = function(e){ |
|
|
|
|
80
|
|
|
$('svg').css('background-color', svg_background_color_offline); |
81
|
|
|
$('header').css('background-color', svg_background_color_offline); |
82
|
|
|
$('.offline-text').css('visibility', 'visible'); |
83
|
|
|
$('.events-remaining-text').css('visibility', 'visible'); |
84
|
|
|
$('.events-remaining-value').css('visibility', 'visible'); |
85
|
|
|
}; |
86
|
|
|
|
87
|
|
|
/** |
88
|
|
|
* This function checks whether an event is already in the queue |
89
|
|
|
*/ |
90
|
|
|
function isEventInQueue(event){ |
91
|
|
|
for(var i=0; i<eventQueue.length; i++){ |
92
|
|
|
if(eventQueue[i].id == event.id) |
93
|
|
|
return true; |
|
|
|
|
94
|
|
|
} |
95
|
|
|
return false; |
96
|
|
|
} |
97
|
|
|
|
98
|
|
|
$(function(){ |
99
|
|
|
element = document.documentElement; |
100
|
|
|
drawingArea = document.getElementsByTagName('#area'); |
101
|
|
|
width = window.innerWidth || element.clientWidth || drawingArea.clientWidth; |
102
|
|
|
height = (window.innerHeight - $('header').height()) || (element.clientHeight - $('header').height()) || (drawingArea.clientHeight - $('header').height()); |
103
|
|
|
$('svg').css('background-color', svg_background_color_online); |
104
|
|
|
$('header').css('background-color', svg_background_color_online); |
105
|
|
|
$('svg text').css('color', svg_text_color); |
106
|
|
|
$('#volumeSlider').slider({ |
107
|
|
|
'max': 100, |
108
|
|
|
'min': 0, |
109
|
|
|
'value': volume*100, |
110
|
|
|
'slide' : function(event, ui){ |
111
|
|
|
volume = ui.value/100.0; |
112
|
|
|
Howler.volume(volume); |
|
|
|
|
113
|
|
|
}, |
114
|
|
|
'change' : function(event, ui){ |
115
|
|
|
volume = ui.value/100.0; |
116
|
|
|
Howler.volume(volume); |
|
|
|
|
117
|
|
|
} |
118
|
|
|
}); |
119
|
|
|
|
120
|
|
|
// Main drawing area |
121
|
|
|
svg = d3.select("#area").append("svg"); |
|
|
|
|
122
|
|
|
svg.attr({width: width, height: height}); |
123
|
|
|
svg.style('background-color', svg_background_color_online); |
124
|
|
|
|
125
|
|
|
// For window resizes |
126
|
|
|
var update_window = function() { |
127
|
|
|
width = window.innerWidth || element.clientWidth || drawingArea.clientWidth; |
128
|
|
|
height = (window.innerHeight - $('header').height()) || (element.clientHeight - $('header').height()) || (drawingArea.clientHeight - $('header').height()); |
129
|
|
|
svg.attr("width", width).attr("height", height); |
130
|
|
|
}; |
131
|
|
|
window.onresize = update_window; |
132
|
|
|
update_window(); |
133
|
|
|
|
134
|
|
|
var loaded_sounds = 0; |
135
|
|
|
var sound_load = function(r) { |
|
|
|
|
136
|
|
|
loaded_sounds += 1; |
137
|
|
|
if (loaded_sounds == total_sounds) { |
138
|
|
|
all_loaded = true; |
139
|
|
|
setTimeout(playFromQueueExchange1, Math.floor(Math.random() * 1000)); |
140
|
|
|
} |
141
|
|
|
}; |
142
|
|
|
|
143
|
|
|
// Load sounds |
144
|
|
|
for (var i = 1; i <= 24; i++) { |
145
|
|
|
if (i > 9) { |
146
|
|
|
fn = 'c0' + i; |
|
|
|
|
147
|
|
|
} else { |
148
|
|
|
fn = 'c00' + i; |
149
|
|
|
} |
150
|
|
|
celesta.push(new Howl({ |
|
|
|
|
151
|
|
|
src : [ |
152
|
|
|
'https://d1fz9d31zqor6x.cloudfront.net/sounds/celesta/' + fn + '.ogg', |
153
|
|
|
'https://d1fz9d31zqor6x.cloudfront.net/sounds/celesta/' + fn + '.mp3' |
154
|
|
|
], |
155
|
|
|
volume : 0.7, |
156
|
|
|
onload : sound_load(), |
157
|
|
|
buffer: true |
158
|
|
|
})); |
159
|
|
|
clav.push(new Howl({ |
160
|
|
|
src : [ |
161
|
|
|
'https://d1fz9d31zqor6x.cloudfront.net/sounds/clav/' + fn + '.ogg', |
162
|
|
|
'https://d1fz9d31zqor6x.cloudfront.net/sounds/clav/' + fn + '.mp3' |
163
|
|
|
], |
164
|
|
|
volume : 0.4, |
165
|
|
|
onload : sound_load(), |
166
|
|
|
buffer: true |
167
|
|
|
})) |
168
|
|
|
} |
169
|
|
|
|
170
|
|
|
for (var i = 1; i <= 3; i++) { |
|
|
|
|
171
|
|
|
swells.push(new Howl({ |
172
|
|
|
src : [ |
173
|
|
|
'https://d1fz9d31zqor6x.cloudfront.net/sounds/swells/swell' + i + '.ogg', |
174
|
|
|
'https://d1fz9d31zqor6x.cloudfront.net/sounds/swells/swell' + i + '.mp3' |
175
|
|
|
], |
176
|
|
|
volume : 1, |
177
|
|
|
onload : sound_load(), |
178
|
|
|
buffer: true |
179
|
|
|
})); |
180
|
|
|
} |
181
|
|
|
|
182
|
|
|
Howler.volume(volume); |
|
|
|
|
183
|
|
|
|
184
|
|
|
// Make $('header') and footer visible |
185
|
|
|
$('body').css('visibility', 'visible'); |
186
|
|
|
|
187
|
|
|
$('#org-repo-filter-name').on('input', function() { |
188
|
|
|
orgRepoFilterNames = $('#org-repo-filter-name').val().split(' '); |
189
|
|
|
eventQueue = []; |
190
|
|
|
}); |
191
|
|
|
|
192
|
|
|
}); |
193
|
|
|
|
194
|
|
|
/** |
195
|
|
|
* Randomly selects a swell sound and plays it |
196
|
|
|
*/ |
197
|
|
|
function playRandomSwell() { |
198
|
|
|
var index = Math.round(Math.random() * (swells.length - 1)); |
199
|
|
|
swells[index].play(); |
200
|
|
|
} |
201
|
|
|
|
202
|
|
|
/** |
203
|
|
|
* Plays a sound(celesta and clav) based on passed parameters |
204
|
|
|
*/ |
205
|
|
|
function playSound(size, type) { |
206
|
|
|
var max_pitch = 100.0; |
207
|
|
|
var log_used = 1.0715307808111486871978099; |
208
|
|
|
var pitch = 100 - Math.min(max_pitch, Math.log(size + log_used) / Math.log(log_used)); |
209
|
|
|
var index = Math.floor(pitch / 100.0 * Object.keys(celesta).length); |
210
|
|
|
|
211
|
|
|
index += Math.floor(Math.random() * 4) - 2; |
212
|
|
|
index = Math.min(Object.keys(celesta).length - 1, index); |
213
|
|
|
index = Math.max(1, index); |
214
|
|
|
if (current_notes < note_overlap) { |
215
|
|
|
current_notes++; |
216
|
|
|
if (type == 'IssuesEvent' || type == 'IssueCommentEvent') { |
217
|
|
|
clav[index].play(); |
218
|
|
|
} else if(type == 'PushEvent') { |
219
|
|
|
celesta[index].play(); |
220
|
|
|
}else{ |
221
|
|
|
playRandomSwell(); |
222
|
|
|
} |
223
|
|
|
setTimeout(function() { |
224
|
|
|
current_notes--; |
225
|
|
|
}, note_timeout); |
226
|
|
|
} |
227
|
|
|
} |
228
|
|
|
|
229
|
|
|
// Following are the n numbers of event consumers |
230
|
|
|
// consuming n events each per second with a random delay between them |
231
|
|
|
|
232
|
|
|
function playFromQueueExchange1(){ |
233
|
|
|
var event = eventQueue.shift(); |
234
|
|
|
if(event != null && event.message != null && svg != null){ |
235
|
|
|
playSound(event.message.length*1.1, event.type); |
236
|
|
|
if(!document.hidden) |
237
|
|
|
drawEvent(event, svg); |
|
|
|
|
238
|
|
|
} |
239
|
|
|
setTimeout(playFromQueueExchange1, Math.floor(Math.random() * 1000) + 500); |
240
|
|
|
$('.events-remaining-value').html(eventQueue.length); |
241
|
|
|
} |
242
|
|
|
|
243
|
|
|
function drawEvent(data, svg_area) { |
244
|
|
|
var starting_opacity = 1; |
245
|
|
|
var opacity = 1 / (100 / data.message.length); |
246
|
|
|
if (opacity > 0.5) opacity = 0.5; |
|
|
|
|
247
|
|
|
|
248
|
|
|
var size = data.message.length; |
249
|
|
|
var label_text; |
250
|
|
|
var ring_radius = 80; |
251
|
|
|
var ring_anim_duration = 3000; |
252
|
|
|
svg_text_color = '#FFFFFF'; |
253
|
|
|
|
254
|
|
|
switch(data.type){ |
|
|
|
|
255
|
|
|
case "PushEvent": |
256
|
|
|
label_text = data.actorName + " pushed to " + data.repoName; |
257
|
|
|
edit_color = '#22B65D'; |
258
|
|
|
break; |
259
|
|
|
case "PullRequestEvent": |
260
|
|
|
label_text = data.actorName + " " + |
261
|
|
|
data.action + " " + " a PR for " + data.repoName; |
262
|
|
|
edit_color = '#8F19BB'; |
263
|
|
|
ring_anim_duration = 10000; |
264
|
|
|
ring_radius = 600; |
265
|
|
|
break; |
266
|
|
|
case "IssuesEvent": |
267
|
|
|
label_text = data.actorName + " " + |
268
|
|
|
data.action + " an issue in " + data.repoName; |
269
|
|
|
edit_color = '#ADD913'; |
270
|
|
|
break; |
271
|
|
|
case "IssueCommentEvent": |
272
|
|
|
label_text = data.actorName + " commented in " + data.repoName; |
273
|
|
|
edit_color = '#FF4901'; |
274
|
|
|
break; |
275
|
|
|
case "ForkEvent": |
276
|
|
|
label_text = data.actorName + " forked " + data.repoName; |
277
|
|
|
edit_color = '#0184FF'; |
278
|
|
|
break; |
279
|
|
|
case "CreateEvent": |
280
|
|
|
label_text = data.actorName + " created " + data.repoName; |
281
|
|
|
edit_color = '#00C0C0'; |
282
|
|
|
break; |
283
|
|
|
case "WatchEvent": |
284
|
|
|
label_text = data.actorName + " watched " + data.repoName; |
285
|
|
|
edit_color = '#E60062'; |
286
|
|
|
break; |
287
|
|
|
} |
288
|
|
|
|
289
|
|
|
var no_label = false; |
|
|
|
|
290
|
|
|
var type = data.type; |
291
|
|
|
|
292
|
|
|
var abs_size = Math.abs(size); |
293
|
|
|
size = Math.max(Math.sqrt(abs_size) * scale_factor, 3); |
294
|
|
|
|
295
|
|
|
Math.seedrandom(data.message); |
296
|
|
|
var x = Math.random() * (width - size) + size; |
297
|
|
|
var y = Math.random() * (height - size) + size; |
298
|
|
|
|
299
|
|
|
var circle_group = svg_area.append('g') |
300
|
|
|
.attr('transform', 'translate(' + x + ', ' + y + ')') |
301
|
|
|
.attr('fill', edit_color) |
302
|
|
|
.style('opacity', starting_opacity); |
303
|
|
|
|
304
|
|
|
var ring = circle_group.append('circle'); |
305
|
|
|
ring.attr({r: size, stroke: 'none'}); |
306
|
|
|
ring.transition() |
307
|
|
|
.attr('r', size + ring_radius) |
308
|
|
|
.style('opacity', 0) |
309
|
|
|
.ease(Math.sqrt) |
310
|
|
|
.duration(ring_anim_duration) |
311
|
|
|
.remove(); |
312
|
|
|
|
313
|
|
|
var circle_container = circle_group.append('a'); |
314
|
|
|
circle_container.attr('xlink:href', data.eventURL); |
315
|
|
|
circle_container.attr('target', '_blank'); |
316
|
|
|
circle_container.attr('fill', svg_text_color); |
317
|
|
|
|
318
|
|
|
var circle = circle_container.append('circle'); |
319
|
|
|
circle.classed(type, true); |
320
|
|
|
circle.attr('r', size) |
321
|
|
|
.attr('fill', edit_color) |
322
|
|
|
.transition() |
323
|
|
|
.duration(max_life) |
324
|
|
|
.style('opacity', 0) |
325
|
|
|
.remove(); |
326
|
|
|
|
327
|
|
|
circle_container.on('mouseover', function() { |
328
|
|
|
circle_container.append('text') |
329
|
|
|
.text(label_text) |
|
|
|
|
330
|
|
|
.classed('label', true) |
331
|
|
|
.attr('text-anchor', 'middle') |
332
|
|
|
.attr('font-size', '0.8em') |
333
|
|
|
.transition() |
334
|
|
|
.delay(1000) |
335
|
|
|
.style('opacity', 0) |
336
|
|
|
.duration(2000) |
337
|
|
|
.each(function() { no_label = true; }) |
|
|
|
|
338
|
|
|
.remove(); |
339
|
|
|
}); |
340
|
|
|
|
341
|
|
|
var text = circle_container.append('text') |
342
|
|
|
.text(label_text) |
|
|
|
|
343
|
|
|
.classed('article-label', true) |
344
|
|
|
.attr('text-anchor', 'middle') |
345
|
|
|
.attr('font-size', '0.8em') |
346
|
|
|
.transition() |
347
|
|
|
.delay(2000) |
348
|
|
|
.style('opacity', 0) |
349
|
|
|
.duration(5000) |
350
|
|
|
.each(function() { no_label = true; }) |
|
|
|
|
351
|
|
|
.remove(); |
352
|
|
|
|
353
|
|
|
// Remove HTML of decayed events |
354
|
|
|
// Keep it less than 50 |
355
|
|
|
if($('#area svg g').length > 50){ |
356
|
|
|
$('#area svg g:lt(10)').remove(); |
357
|
|
|
} |
358
|
|
|
} |
359
|
|
|
|
Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.
Consider:
If you or someone else later decides to put another statement in, only the first statement will be executed.
In this case the statement
b = 42
will always be executed, while the logging statement will be executed conditionally.ensures that the proper code will be executed conditionally no matter how many statements are added or removed.